package com.mes.schedule.manager;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.mes.basicdata.domain.CalendarData;
import com.mes.common.spring.SpringUtils;
import com.mes.schedule.domain.DeviceStatistics;
import com.mes.schedule.domain.OperationTasksAssign;
import com.mes.schedule.domain.SCalendar;
import com.mes.schedule.domain.SDevice;
import com.mes.schedule.domain.SOperationTask;
import com.mes.schedule.domain.ScheduleScheme;
import com.mes.schedule.domain.TimeSection;
import com.mes.schedule.manager.iface.IScheduleDeviceManager;
import com.mes.schedule.util.ScheduleUtils;


@Component("scheduledeviceManager")
@Transactional
public class ScheduleDeviceManager extends ScheduleResourceManager implements IScheduleDeviceManager{
	private final static Log log = LogFactory.getLog(ScheduleDeviceManager.class);

	public void calDeviceStatistics(SDevice device, ScheduleScheme scheme) {
		if (scheme.getScheduleDays() == null)
			return;
		int interval = scheme.getScheduleInterval();
		int scheduleDays = scheme.getScheduleDays();
		if (device.getCalendar() == null)
			return;
		Date startDate = device.getCalendar().getStartDate();
		if (device.getResCapacity() == 1) {
			calculation(device, startDate, interval, scheduleDays);
		} else {
			// if(device.getResCapacity()>1){
			// Calendar temp = Calendar.getInstance();
			// temp.setTime(startDate);
			// for (int i = 0; i < device.getVirtualDeviceList().size(); i++) {
			// calculation(device.getVirtualDeviceList().get(i), startDate,
			// interval, scheduleDays);
			// }
			// List<DeviceStatistics> deviceStatList = new
			// ArrayList<DeviceStatistics>();
			//
			// double totalLoad = 0;
			// double totalUtil = 0;
			// for (int j = 0; j < scheduleDays; j++) {
			// double load = 0;
			// double util = 0;
			// int size = device.getVirtualDeviceList().size();
			// for (int i = 0; i < size; i++) {
			// Device d = device.getVirtualDeviceList().get(i);
			// load += d.getDeviceStatList().get(j).getLoadRation();
			// util += d.getDeviceStatList().get(j).getUtilRation();
			//
			// }
			// load /= size;
			// util /= size;
			// totalLoad += load;
			// totalUtil += util;
			// DeviceStatistics stat = new DeviceStatistics();
			// stat.setDate(temp.getTime());
			// stat.setLoadRation(load);
			// stat.setUtilRation(util);
			// deviceStatList.add(stat);
			// temp.add(Calendar.DAY_OF_YEAR, 1);
			// }
			// device.setAverageLoadRation(totalLoad/scheduleDays);
			// device.setAverageUtilRation(totalUtil/scheduleDays);
			// device.setDeviceStatList(deviceStatList);
			// }

		}

	}

	private void calculation(SDevice device, Date startDate, int interval, int scheduleDays) {
		try {
			List<DeviceStatistics> deviceStatList = new ArrayList<DeviceStatistics>();

			Calendar temp = Calendar.getInstance();
			temp.setTime(startDate);

			int periodPerDay = 1440 / interval;
			int init = 0;

			int totalCount = 0;
			int totalLoad = 0;
			int totalUtil = 0;

			SCalendar scalendar = (SCalendar) (device.getCalendar().getSameWithBase()
					? device.getCalendar().getBaseCalendar() : device.getCalendar());

			for (int i = 0; i < scheduleDays; i++) {
				int from = i * periodPerDay + init;
				int to = from + periodPerDay;
				int count = 0;
				int load = 0;
				int util = 0;
				for (int j = from; j < to; j++) {
					System.out.println("1");
					int segementCalendar = this.scheduleCalendarManager.getSegementCalendar(scalendar, j);

					if (segementCalendar == SDevice.DEVICE_NOMAL || segementCalendar == SDevice.DEVICE_OVERTIME) {
						count++;
						if (device.getSegementUse(j) == SDevice.DEVICE_PROCESS) {
							load++;
							util++;
						} else if (device.getSegementUse(j) == SDevice.DEVICE_SETUP) {
							load++;
						}
					}

				}

				double loadRation = 0;
				double utilRation = 0;
				if (count > 0) {
					utilRation = (double) util / count;
					loadRation = (double) load / count;
				} else {
					utilRation = 0;
					loadRation = 0;
				}
				DeviceStatistics stat = new DeviceStatistics();
				stat.setDate(temp.getTime());
				stat.setLoadRation(loadRation);
				stat.setUtilRation(utilRation);
				deviceStatList.add(stat);
				temp.add(Calendar.DAY_OF_YEAR, 1);

				totalCount += count;
				totalLoad += load;
				totalUtil += util;

			}
			device.setDeviceStatList(deviceStatList);
			double averageLoadRation = 0;
			double averageUtilRation = 0;
			if (totalCount > 0) {
				averageLoadRation = (double) totalLoad / totalCount;
				averageUtilRation = (double) totalUtil / totalCount;
			}
			// averageUtilRation=0.5;
			device.setAverageLoadRation(averageLoadRation);
			device.setAverageUtilRation(averageUtilRation);
		} catch (Exception e) {
			//getSegementCalendar
			e.printStackTrace();
		}
	}

	public void calcWaitTime(SDevice device, ScheduleScheme scheme) {
		double waitTime = 0.0;
		Date Now = scheme.getScheduleStart();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(Now);
		calendar.add(Calendar.DAY_OF_YEAR, scheme.getScheduleDays());
		Date deadLine = calendar.getTime();
		TreeMap<TimeSection, SOperationTask> operTask = device.getOperTask();
		Set<Entry<TimeSection, SOperationTask>> entrySet = operTask.entrySet();
		Iterator<Entry<TimeSection, SOperationTask>> it = entrySet.iterator();
		while (it.hasNext()) {
			Entry<TimeSection, SOperationTask> entry = it.next();
			if (entry.getValue().getPlanStart().before(deadLine)) {
				waitTime += entry.getValue().getWaitTime();
			}
			if (entry.getValue().getPlanStart().after(deadLine)) {
				break;
			}
		}
		device.setTotalWaitTime(waitTime);

	}

	public void saveDeviceException(SDevice device, ScheduleScheme scheme, List<CalendarData> calendarDataList)
			throws Exception {
		// TODO Auto-generated method stub
		String calendarUid = device.getCalendarUid();
		for (CalendarData cd : calendarDataList) {
			cd.setCalendarUid(calendarUid);
			cd.setDayOrException(0);
		}
//		calendarDataManager.save(calendarDataList);

	}

	public List<CalendarData> getDeviceException(SDevice device, ScheduleScheme scheme) throws Exception {
		if (device.getCalendar() != null)
			return device.getCalendar().getSelfExceptionCalendarData();

		return null;

	}

	public void updateDeviceCalendar(String scheduleUid, String deviceUid, SCalendar calendar,
			List<CalendarData> calendarDataList) throws Exception {
		ScheduleScheme scheme = ScheduleUtils.getScheduleScheme(scheduleUid);
		SDevice device = scheme.getDeviceMap().get(deviceUid);
		calendar.setScheme(scheme);
		// 设置设备的例外日历
		calendar.setExceptionCalendarData(calendarDataList);
		scheduleCalendarManager.updateCalendar(calendar);

		// 只是更新日历

		// device.setCalendar(scheme.getCalendarMap().get(calendar.getUuid()));

		// this.calendarManager.initCalendar(scheme, calendar.getCalendarUid());
		// 重新初始化该设备的日历，影响该设备的能力信息
		// this.initDevice(device);

	}

	//
	// public void initDevice(Device device) throws Exception {
	//
	// if (device instanceof McDevice) {
	// for (Device vd : ((McDevice) device).getVirtualDeviceList()) {
	// initDevice(vd);
	// }
	// return;
	// }
	// if (device instanceof MtDevice) {
	// for (DeviceTable dt : ((MtDevice) device).getTableList()) {
	// initDevice(dt);
	// }
	// // return;//需要同时同步主资源，作为主轴资源
	// }
	// log.debug("开始初始化设备：" + device.getDeviceName() + " "
	// + device.getDeviceUid());

	// device.setCapacity(calendarManager.createTimeGrid(device.getCalendar()));

	// device.setCapacity(capacity);
	// ScheduleScheme scheme = device.getScheme();
	// int interval = scheme.getScheduleInterval();
	// SCalendar calendar = device.getCalendar();
	// if(calendar==null)
	// throw new Exception(device+" 对应的设备日历不存在,日历编号为:"+device.getCalendarUid());

	// int totalSegment =scheme.getTotalSegement();
	// int[][] capacity = new int[totalSegment][2];
	// device.setCapacity(capacity);
	// // int[] state = new int[totalSegment];
	// if(calendar.getTimeSection()==null)
	// throw new Exception(device+"
	// 对应的设备日历尚未初始化,日历编号为:"+device.getCalendarUid());
	// TreeMap<TimeSection, Integer> timeSection = calendar.getTimeSection();
	// Set<Entry<TimeSection, Integer>> entries = timeSection.entrySet();
	// Iterator<Entry<TimeSection, Integer>> itor = entries.iterator();
	// long lastEnd = 0;
	// int count = 0;
	// while (itor.hasNext()) {
	// Entry<TimeSection, Integer> k = itor.next();
	// int unavalibleCount = Math.round((k.getKey().getStart() - lastEnd)
	// / (float) interval);
	//
	// // throw java.lang.ArrayIndexOutOfBoundsException :35168
	// for (int i = count; i < totalSegment && i < count + unavalibleCount; i++)
	// {
	// capacity[i][0] = Device.DEVICE_CLOSINGTIME;
	// }
	// count += unavalibleCount;
	// int avalibleCount = Math.round((k.getKey().getEnd() - k.getKey()
	// .getStart())
	// / (float) interval);
	// //暂时加班,例外，正常加班没有区别
	// //todo,以后要考虑
	// if (k.getValue() >= 1) {
	// for (int i = count; i < totalSegment
	// && i < count + avalibleCount; i++) {
	// capacity[i][0] = Device.DEVICE_NOMAL;
	// capacity[i][1] = Device.DEVICE_IDLE;
	//
	// }
	// }
	// //暂时加班,例外，正常加班没有区别
	//
	// // if (k.getValue() == 2) {
	// // for (int i = count; i < totalSegment
	// // && i < count + avalibleCount; i++) {
	// // capacity[i][0] = Device.DEVICE_OVERTIME;
	// // capacity[i][1] = Device.DEVICE_IDLE;
	// //
	// // }
	// // }
	// count += avalibleCount;
	// lastEnd = k.getKey().getEnd();
	// }
	// if (lastEnd / interval != totalSegment) {
	// int unavalibleCount = (int) (totalSegment - lastEnd / interval);
	// for (int i = (int) lastEnd / interval; i < unavalibleCount; i++) {
	// capacity[i][0] = Device.DEVICE_CLOSINGTIME;
	// }
	// }

	// }

	/**
	 * get the device list
	 * 
	 * @param scheduleUid
	 * @return
	 * @throws Exception
	 */

	public List<SDevice> getDeviceList(ScheduleScheme scheme) throws Exception {
		List<SDevice> deviceList = new ArrayList<SDevice>();

		if (scheme == null) {
			return null;
		}
		if (scheme.getDeviceMap() != null) {
			for (SDevice device : scheme.getDeviceMap().values()) {
				if (!device.getVirtual()) {
					deviceList.add(device);
				}

			}
		}
		/*
		 * Collections.sort(deviceList, new Comparator<Object>() { public int
		 * compare(Object o1, Object o2) { Device d1 = (Device) o1; Device d2 =
		 * (Device) o2; int i = 0; if
		 * (d1.getDeviceClass().compareTo(d2.getDeviceClass()) > 0) { i = 1; }
		 * return i; } });
		 */
		Collections.sort(deviceList, new Comparator<Object>() {
			public int compare(Object o1, Object o2) {
				SDevice d1 = (SDevice) o1;
				SDevice d2 = (SDevice) o2;
				int i = -1;
				if (d1.getDeviceClassName().compareTo(d2.getDeviceClassName()) > 0)
					i = 1;
				else if (d1.getDeviceClassName().compareTo(d2.getDeviceClassName()) == 0) {
					if (d1.getDeviceName().compareTo(d2.getDeviceName()) > 0) {
						i = 1;
					}
				}
				return i;
			}
		});

		return deviceList;
	}

	public TreeSet<SDevice> getDevicesOrderByCritical(ScheduleScheme scheme) {
		// TODO Auto-generated method stub
		TreeSet<SDevice> devices = new TreeSet<SDevice>(new Comparator<SDevice>() {
			public int compare(SDevice device1, SDevice device2) {
				int i;
				if (device1.equals(device2))
					return 0;
				if (device1.getCriticalLevel() > device2.getCriticalLevel())// criticalLevel
					i = 1;
				else
					i = -1;
				return i;
			}
		});
		;
		// tod
		// 可能用Collections.sort()
		for (SDevice device : scheme.getDeviceMap().values()) {
			devices.add(device);
		}
		return devices;
	}

	public void preassignTask(SDevice device, SOperationTask operationTask) {
		// TODO Auto-generated method stub

	}

	public int getAvailableSegementCount(SDevice device, Date fromDate, Date toDate) {
		// TODO Auto-generated method stub
		ScheduleScheme scheme = device.getScheme();
		int fromSegement = scheme.calSegementFromDate(fromDate);
		int toSegement = scheme.calSegementFromDate(toDate);
		int count = 0;

		for (int i = fromSegement; i < toSegement; i++) {
			int iC = this.getSegementCalendar(device, i);
			if (iC == SCalendar.CALENDAR_NOMAL || iC == SCalendar.CALENDAR_OVERTIME)
				count++;
		}

		return count;
	}

	public Date calFinishTime(SDevice device, Date startTime, double estiTaskWork) {
		ScheduleScheme scheme = device.getScheme();
		int needSegment = (int) Math.round(estiTaskWork / scheme.getScheduleInterval());
		int i = scheme.calSegementFromDate(startTime);
		int freeCount = 0;
		while (freeCount < needSegment) {
			int iC = this.getSegementCalendar(device, i);
			if (iC == SCalendar.CALENDAR_NOMAL || iC == SCalendar.CALENDAR_OVERTIME)
				freeCount++;
			i++;
		}
		return scheme.calDateFromSegement(i);
	}

	@Transactional

	public void beginMaint(SDevice device, Date planResumeTime) throws Exception {
		ScheduleScheme scheme = device.getScheme();
		if (device.getCalendar() == null) {
			log.warn("设备日历为空" + device);
			return;
		}

		// 设置设备的例外日历
		CalendarData calendarData = new CalendarData();
		calendarData.setCalendarUid(device.getCalendar().getCalendarUid());
		calendarData.setDayOrException(0);
		calendarData.setExceptionType(CalendarData.EXCEPTION_TYPE_MAINTENANCE);
		calendarData.setIsWorking(false);
		Date fromDate = new Date();
		calendarData.setFromDate(fromDate);
		if (planResumeTime == null || planResumeTime.before(fromDate)) {
			Calendar calendar = Calendar.getInstance();
			// 缺省增加一天
			// 应该参数化
			calendar.setTime(fromDate);
			calendar.add(Calendar.DATE, 1);
			planResumeTime = calendar.getTime();
		}
		calendarData.setToDate(planResumeTime);

		calendarDataManager.add(calendarData);

		// calendarDataManager.getBasicDao().flush();

		scheduleCalendarManager.initCalendar(scheme, device.getCalendar().getCalendarUid());
	}

	@Transactional

	public void recoveryMaint(SDevice device) throws Exception {
		ScheduleScheme scheme = device.getScheme();
		SCalendar calendar = device.getCalendar();
		if (calendar == null) {
			log.warn("设备日历为空" + device);
			return;
		}
		List<CalendarData> calendarDataList = calendar.getExceptionCalendarData();
		if (calendarDataList != null && calendarDataList.size() > 0) {
			for (CalendarData calendarData : calendar.getExceptionCalendarData()) {
				if (CalendarData.EXCEPTION_TYPE_MAINTENANCE.equals(calendarData.getExceptionType())) {
					calendarData.setIsEffective(false);
					calendarData.setInvalidDate(new Date());
					// calendarData.setNotes(notes)
					this.calendarDataManager.update(calendarData);

					// 万一工人点了多次维修
					// break;
				}

			}
		}
		// calendarDataManager.getBasicDao().flush();
		scheduleCalendarManager.initCalendar(scheme, calendar.getCalendarUid());

	}

	public int calCapacity(SDevice device, Date beforeDate) {
		if (device == null || beforeDate == null)
			return 0;
		ScheduleScheme scheme = device.getScheme();
		int iEnd = scheme.calSegementFromDate(beforeDate);
		int freeCount = 0;
		int iCapacity = 0;
		for (int i = 1; i <= iEnd; i++) {
			int iC = this.getSegementCalendar(device, i);
			if (iC == SCalendar.CALENDAR_NOMAL || iC == SCalendar.CALENDAR_OVERTIME)
				iCapacity++;
		}
		// if(device instanceof McDevice)
		// return iCapacity*scheme.getScheduleInterval()*((McDevice)device.);
		// else
		return iCapacity * scheme.getScheduleInterval() * device.getResCapacity();
	}

	public List<SOperationTask> getMaybeDoList(SDevice device, Date beforeDate) {
		// TODO Auto-generated method stub
		return null;
	}

	public List<SOperationTask> getMaybeDoList(SDevice device, Date afterDate, String drawingId,
			Integer maxTaskInstance) {
		// TODO Auto-generated method stub
		return null;
	}

	public List<SOperationTask> getMustDoList(SDevice device, Date beforeDate) {
		// TODO Auto-generated method stub
		return null;
	}

	public List<SOperationTask> getMustDoList(SDevice device, Date beforeDate, String drawingId,
			Integer maxTaskInstance) {
		// TODO Auto-generated method stub
		return null;
	}

	public int calFinishSegement(SDevice device, int startSegement, double estiTaskWork) {
		ScheduleScheme scheme = device.getScheme();
		int needSegment = (int) Math.round(estiTaskWork / scheme.getScheduleInterval());
		int i = startSegement;
		int freeCount = 0;
		int totalSegment = scheme.getTotalSegement();
		while (freeCount < needSegment && i < totalSegment) {
			int iC = this.getSegementCalendar(device, i);
			if (iC == SCalendar.CALENDAR_NOMAL || iC == SCalendar.CALENDAR_OVERTIME)
				freeCount++;
			i++;
		}
		return i;
	}

	/**
	 * fpc 根据工序号和调度方案得到可分配的设备上工序任务数量、负荷、能力等
	 */
	public List<OperationTasksAssign> getOperationTaskAssignedToDeviceList(String scheduleUid, String opTaskUid)
			throws Exception {
		ScheduleSchemeManager scheduleSchemeManager = SpringUtils.getBean("schemeManager");

		ScheduleScheme scheme = scheduleSchemeManager.getScheduleScheme(scheduleUid);
		if (scheme == null) {
			return null;
		}
		// 今天向后推5天
		Date date = new Date();// 取时间
		Calendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.add(calendar.DATE, scheme.getShiftPlanDays());// 把日期往后增加五天.整数往后推,负数往前移动
		date = calendar.getTime(); // 这个时间就是日期往后推五天的结果

		List<OperationTasksAssign> operationTasksAssignList = new ArrayList<OperationTasksAssign>();// 需要返回的list

		SOperationTask sOperationTask = scheduleSchemeManager.getOperationTask(scheduleUid, opTaskUid);
		if (sOperationTask == null) {
			return operationTasksAssignList;
		}
		String deviceClassUid = sOperationTask.getDeviceClass();

		List<SDevice> deviceList = scheduleSchemeManager.getDeviceList(scheduleUid);
		if (deviceList == null || deviceList.isEmpty())
			return null;
		if (deviceClassUid != null || deviceClassUid != "") {
			for (SDevice device : deviceList) {
				if (device.getDeviceClass().equals(deviceClassUid)) {
					OperationTasksAssign operationTasksAssign = new OperationTasksAssign();

					operationTasksAssign.setDeviceClass(sOperationTask.getDeviceClass());
					operationTasksAssign.setDeviceClassName(sOperationTask.getDeviceClassName());

					operationTasksAssign.setDeviceUid(device.getDeviceUid());
					operationTasksAssign.setDeviceName(device.getDeviceName());

					double capacity = this.calCapacity(device, date);
					int operationTaskCount = 0;
					double load = 0.0;
					List<SOperationTask> opList = scheduleSchemeManager.getTasksAssignedDevice(scheduleUid,
							device.getDeviceUid(), "", date);
					for (SOperationTask op : opList) {
						operationTaskCount++;
						double preTime = op.getEstiPreTime() == null ? 0d : op.getEstiPreTime();
						double runTime = op.getEstiRunTime() == null ? 0d : op.getEstiRunTime();
						load = preTime + runTime * (op.getPlanQty() - op.getCompleteQty()); // 某个工序的加工时间
					}
					operationTasksAssign.setResLoad(load / 60);
					operationTasksAssign.setCapacity(capacity / 60);
					operationTasksAssign.setResUtilize((double) (load / capacity));
					operationTasksAssign.setOperationTaskCount(operationTaskCount);
					operationTasksAssignList.add(operationTasksAssign);
				}
			}
		}
		return operationTasksAssignList;
	}

	@Override
	public List<SDevice> getDeviceList(String deptId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void updateDeviceCalendar(SDevice device, SCalendar calendar) throws Exception {
		// TODO Auto-generated method stub
		
	}

	//
	// /*
	// * 取得资源线程
	// */
	// private ScheduleDeviceThread getScheduleDeviceThread(String resUid)
	// {
	// if(deviceThreadMap.containsKey(resUid))
	// return deviceThreadMap.get(resUid);
	// else
	// {
	// ScheduleResourceThread scheduleResourceThread=new
	// ScheduleResourceThread(this.deviceThreadGroup ,resUid);
	// scheduleResourceThread.start();//只启动一次
	//
	// deviceThreadMap.put(resUid, scheduleResourceThread);
	// return deviceThreadMap;
	// }
	//
	//
	// }

}
